webpack 简介
webpack 是一个模块打包工具。它使得模块相互依赖并且可构建等价于这些模块的静态资源。相比于已经存在的模块打包器(module bundler),webpack的开发动机是实现代码分包(Code Splitting )和通过模块化完成代码的无缝集成。webpack可以根据项目需求合并代码,并且支持按需加载。
使用 webpack 目的是:
- 拆分依赖树(dependency tree)为多个按需加载的chunk
- 保证快速首屏加载
- 每种静态资源都可成为模块
- 能够将第三方库视作一个模块来处理
- 能够定制模块打包器的几乎任何部分
- 适合大型项目
webpack 基本使用
安装webpack之前,请确认node已经安装完毕,且npm包管理器可用(这里不做详细介绍,自己搜索教程吧)。
全局安装 webpack
1 | npm install webpack -g |
全局安装 webpack-dev-server
1 | npm install webpack-dev-server -g |
项目搭建,webpack 配置
执行以下命令,新建项目文件夹airplan,并进入项目文件夹初始化项目基本信息
1 | mkdir airplan |
执行完以上命令后,会生成 package.json
,内容大致如下:
1 | { |
在当前项目根路径下执行
1 | npm install webpack --save-dev |
(关于 npm install webpack --save
和 npm install webpack --save-dev
的区别:前者安装完是在生产环境下,后者在开发环境下,什么意思看截图大概都能懂,不懂自己搜索吧),如图:
执行完后,新建 webpack.config.js
。我们通过这个文件来处理控制 webpack
,给出我们想要的输出。
以下是我当前项目的路径:
webpack.config.js
简单的配置如下:
1 | module.exports = { |
开发调试
在项目根目录运行:
1 | webpack-dev-server --progress --colors |
此时,访问:http://localhost:8080/index.bundle.js 即可访问到编译之后的js了。
产品发布
通过webpack打包发布,运行:
1 | webpack -p |
按照我们上面的webpack.config.js文件的配置,打包成功之后会生成一个build文件夹,里面会包含打包好的js文件,集成了所有的依赖库和业务逻辑代码,我们只需将此build文件夹发布到线上即可。
至此一个完整流程的webpack运行流程梳理完毕,当然webpack还有很多功能来实现我们开发中所遇到的各种变态需求,在第三章中我抽出了一些项目中常用的功能。
常用功能
设置入口
配置那些js需要处理,entry有三种写法,每个入口称为一个chunk。
字符串
entry: “./index/index.js” : 配置模块会被解析为模块,并在启动时加载。chunk名为默认为main, 具体打包文件名视output配置而定。数组
entry: [‘./src/mod1.js’, […,] ‘./src/index.js’] : 所有的模块会在启动时按照配置顺序加载,合并到最后一个模块会被导出。chunk名默认为main。对象
entry: {index: ‘…’, login : […] } : 如果传入Object,则会生成多个入口打包文件,key是chunk名,value可以是字符串,也可是数组。
举个栗子:
1 | entry: { |
配置输出目录
设置入口配置的文件的输出规则,通过output对象实现,常用设置:
1 | output: { |
其中:
- output.path : 指定输出文件路径,通常设置为
__dirname + '/build'
。 output.filename : 输出文件名称,有下面列出的四种可选的变量。 filename项的配置可以是这几种的任意一种或多种的组合。 如
output.filename = '[name]-[id].js'
, 则输出就是index-1.js
、login-2.js
。- [id] : chunk的id
- [name] : chunk名
- [hash] : 编译哈希值
- [chunkhash] : chunk的hash值
output.publicPath : 设置为想要的资源访问路径。访问时,则需要通过类似 http://localhost:8080/asstes/index-1.js 来访问资源,如果没有设置,则默认从站点根目录加载。
设置loader
loader是webpack中比较重要的部分,她是处理各类资源的执行者。它们是一系列的函数(运行在node.js中),将资源中的代码作为参数,然后返回新的代码。你可以用loader告诉webpack可以加载哪些文件,或者不加载哪些文件。
Loader 的特点:
- 可以链式执行。它们在一个管道中被提交,只需要保证最后的loader返回JavaScript即可,其他loader可以返回任意方便下一个loader处理的内容。
- 可以异步or同步执行
- 运行在Node.js中,可以做几乎任何事儿
- 可以接收query参数,用于向loader传递参数
- 配置中可与正则/扩展结合使用
- 可以在npm中发布并使用
- 除了main,其他模块可以导出成loader
- 可以通过配置调入
- 和插件(plugins)配合可获得更多功能
- 可生成其他格式文件
安装 loader
1 | npm install xxx-loader --save |
或者
1 | npm install xxx-loader --save-dev |
其中,XXX为webpack支持的loader名,常用的有:html、css、jsx、coffee、jade、less、sass、style等。
你可以通过webpack loader 列表 查看所有支持的loader。当然你可以自己根据需求创建并发布loader。
配置 loader
1 | modules: { |
多loader调用示例
在js中,如果要直接解析某个文件,你可以采用:
1 | require("jade!./index.jade"); |
如果要解析css,需要使用到分隔符 ! :
1 | require("!style!css!./style.css"); |
同理,如果要解析less, 转换成css之后,写法如:
1 | require("!style!css!less!./style.less"); // 此语句的含义是,先调用less-loader解析style.less文件,输出结果会被css-loader处理, 然后再被style-loader处理 |
同理,在webpack.config.js配置文件中,只需要制定处理的loader序列:
即:
1 | ... |
本章会介绍比较常用的loader的配置方法。
解析并抽取css
在webpack中css默认方案是,将css编译并通过内联的方式在html页面中插入 <style>
样式标签。当然这远远不能满足我们的要求,webpack提供 css-loader
模块用于编译css文件,并且提供了插件 extract-text-webpack-plugin
将css从js代码中抽出并合并。你可以访问此处,查看文档和例子。
这样你可以在模块中,尽情使用 require(style.css)
, webpack会帮你做解析,合并entry中定义js及其依赖中所用到的所有css,然后生成一个指定的css文件。
配置如下:
1 | 'use strict'; |
处理图片、字体等文件
在css中或者js逻辑中,都会涉及到require图片的情况,webpack可以内联图片地址到打包js中并且通过 require()
返回图片路径。当然,不只是图片,还有css中用到的iconfont,特殊情况用到的flash等,都可以相似处理。这里,我们需要用到 url-loader
或 file-loader
。
file-loader
: 将匹配到的文件复制到输出文件夹,并根据 output.publicPath
的设置返回文件路径url-loader
: 类似 file-loader
, 但是它可以返回一个 DataUrl(base 64)
如果文件小于设置的限制值limit。
同样,在这之前,你需要实现配置相关loader。
安装 url-loader
和 file-loader
:
1 | npm install url-loader file-loader --save-dev |
配置:
1 | module:{ |
通过向 url-loader
传递参数,如果图片小于8kb,则base64内联,大于8kb,则通过 output.publishPath
配置的前缀将图片路径写入代码,并提取图片到输出目录。
解析JSX
在React项目中,需要解析JSX和相关JavaScript文件,需要下载loader:
1 | npm install react-hot-loader jsx-loader --save-dev |
同样,配置loader:
1 | ... |
解析ES6语法
babel可以让我们在编写代码的时候,使用更高级的 ECMAScript6 的语法。然后我们编写的JS文件可以被编译成可被低版本浏览器处理的常规代码。
使用方法
安装loader:
1 | npm install babel-loader --save-dev |
配置loader:
1 | loaders: [ |
栗子:
1 | const a = 1; |
解析为:
1 | var a = 1; |
借助 web_modules 引用外部库
有些时候,我们用到的第三方库并没有采用CommonJS或AMD规范,也没有提交到npm。这样的话,我们无法通过npm来下载,并通过require()
来引用这些库。
webpack给我们提供了一个很好的实现方式。我们可以在项目根目录下,创建一个叫做 web_modules
的文件夹,然后将需要用到的第三方库存放在此处。那么之后,不需要做任何设置,可以在我们的逻辑代码中使用 require('xx-lib.js')
并且使用了。
文件目录:
此时,我们就可以在业务逻辑中,大胆地使用 web_modules
中配置的库了,打包的时候,webpack会自动将 web_modules
中被用到的库封装。
栗子:
1 | var director = require('director') |
去除多个文件中的频繁依赖
当我们经常使用React、jQuery等外部第三方库的时候,通常在每个业务逻辑JS中都会遇到这些库。
如我们需要在各个文件中都是有jQuery的$对象,因此我们需要在每个用到jQuery的JS文件的头部通过 require('jquery')
来依赖jQuery。 这样做非常繁琐且重复,因此webpack提供了我们一种比较高效的方法,我们可以通过在配置文件中配置使用到的变量名,那么webpack会自动分析,并且在编译时帮我们完成这些依赖的引入。
webpack.config.js
中:
1 | var webpack = require('webpack'); |
这样,我们在JS中,就不需要引入jQuery等常用模块了,直接使用配置的这些变量,webpack就会自动引入配置的库。
开发环境与发布环境配置
某些情况,我们需要在页面中输出开发调试内容,但是又不想让这些调试内容在发布的时候泄露出去,那么我们可以采用魔力变量(magic globals)来处理。
配置文件:
1 | var webpack = require('webpack'); |
业务逻辑代码中写入:
1 | if (__DEV__) { |
按照上面的代码写入,我们就可以在我们自己设定的环境下进行更具针对性的调试。比如我们希望在开发环境下可以AJAX可以调试本地mock数据,然后在发布的时候,可以正常访问服务端数据。那么通过此种方式可以完全实现。
设置环境命令
我们可以在 package.json
中事先定义好命令:
1 | "scripts": { |
要告诉webpack我们希望当前是什么环境,只需要在命令中写入 BUILD_DEV=1 webpck
那么webpack通过配置,就会将所有我们引用到的 __DEV__
变量设置为true。
那么就可以避免输入冗长的命令了。
开发时输入:
1 | npm run dev |
发布时输入:
1 | npm run build |
使用 devtool 调试
可以通过在配置中加入devtool项,选择预设调试工具来提高代码调试质量和效率:
- eval : 每个模块采用eval和 //@ sourceURL 来执行
- source-map : sourceMap是发散的,和
output.sourceMapFilename
协调使用 - hidden-source-map : 和source-map类似,但是不会添加一个打包文件的尾部添加引用注释
- inline-source-map : SourceMap以DataUrl的方式插入打包文件的尾部
- eval-source-map : 每个模块以eval方式执行并且SourceMap以DataUrl的方式添加进eval
- cheap-source-map : 去除column-mappings的SourceMap,来自于loader中的内容不会被使用
- cheap-module-source-map : 去除column-mappings的SourceMap,来自于loader中的SourceMaps被简化为单个mapping文件
各种模式的对比:
devtool | 构建速度 | 再次构建速度 | 支持发布版 | 质量 |
---|---|---|---|---|
eval | +++ | +++ | no | 生成代码 |
cheap-eval-source-map | + | ++ | no | 转换代码(lines only) |
cheap-source-map | + | o | yes | 转换代码(lines only) |
cheap-module-eval-source-map | o | ++ | no | 源代码(lines only) |
cheap-module-source-map | o | - | yes | 源代码(lines only) |
eval-source-map | - | + | no | 源代码 |
source-map | - | - | yes | 源代码 |
常用的配置
为了方便大家摘取,和补全文章中用于示例的代码片段,特将配置文件整理如下,作参考:
配置文件:
1 | var webpack = require('webpack'); |